<template>
	<view class="mapping-details" ref="uv-back-top">
		<uv-navbar v-if="!isPc" title="成图" @rightClick="routed('/pages/mapping/history')" rightText="历史"
			leftIconSize="10px" :placeholder="true" @leftClick="navigateBack"></uv-navbar>


		<view class="content">
			<view style="height: 50px;width: 100%;cursor: pointer;" @click="uploadFile">
				<uv-icon size="30" style="margin: 10px;" name="photo"></uv-icon>
			</view>
		</view>
		<uv-back-top :scroll-top="scrollTop"></uv-back-top>
		<tabbars :prop-value="'mapping'"></tabbars>
	</view>
</template>

<script>
	// 引入
	import tabbars from '@/components/tabbar/tabbar.vue';
	import Md5 from 'js-md5';
	import CryptoJS from 'crypto-js';
	import config from '@/common/config'
	import {
		uploadFileName,
		postName
	} from '@/common/api.js';
	export default {
		components: {
			// 注册组件
			tabbars,
		},
		data() {
			return {
				scrollTop: 0,
				// 上传
				CHUNK_SIZE: 1024 * 1024 * 5,
				fileHash: '',
				totalChunks: '',
			}
		},
		computed: {},
		onLoad() {},
		onPageScroll(e) {
			this.scrollTop = e.scrollTop;
			// #ifdef APP-NVUE
			this.scrollTop = e.detail.scrollTop;
			// #endif
		},
		methods: {
			// 计算文件MD5
			async calculateFileHash(file) {
				return new Promise((resolve, reject) => {
					// #ifdef H5
					// H5环境：使用FileReader
					const reader = new FileReader();
					reader.readAsArrayBuffer(file);
					reader.onload = (e) => {
						const arrayBuffer = e.target.result;
						const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer);
						const hash = CryptoJS.MD5(wordArray).toString();
						resolve(hash);
					};
					reader.onerror = reject;
					// #endif

					// #ifndef H5
					// 小程序环境：使用文件系统API分片读取并计算MD5
					this.calculateFileHashMiniProgram(file.tempFilePath).then(resolve).catch(reject);
					// #endif
				});
			},
			// 小程序环境计算文件MD5
			calculateFileHashMiniProgram(filePath) {
				return new Promise((resolve, reject) => {
					const fs = uni.getFileSystemManager();

					// 先获取文件信息
					fs.getFileInfo({
						filePath: filePath,
						success: (fileInfo) => {
							const fileSize = fileInfo.size;
							const chunkSize = 1024 * 1024; // 1MB 分片读取
							let currentPosition = 0;
							let md5 = CryptoJS.algo.MD5.create();

							const readNextChunk = () => {
								if (currentPosition >= fileSize) {
									// 读取完成，计算最终hash
									const hash = md5.finalize().toString();
									resolve(hash);
									return;
								}

								const length = Math.min(chunkSize, fileSize - currentPosition);

								fs.readFile({
									filePath: filePath,
									position: currentPosition,
									length: length,
									success: (res) => {
										// 将ArrayBuffer转换为WordArray
										const wordArray = CryptoJS.lib.WordArray
											.create(res.data);
										md5.update(wordArray);
										currentPosition += length;
										readNextChunk();
									},
									fail: reject
								});
							};

							// 开始读取
							readNextChunk();
						},
						fail: reject
					});
				});
			},
			async constructor(file) {
				this.fileHash = await this.calculateFileHash(file.tempFile);
				this.chunkSize = 5 * 1024 * 1024; // 5MB
				this.totalChunks = Math.ceil(file.size / this.chunkSize);
			},
			// 检查上传状态
			async checkStatus(file) {
				const res = await postName('/document/check-status', {
					fileHash: this.fileHash,
					fileName: file.name,
					totalChunks: this.totalChunks
				}, {
					custom: {
						auth: true,
						toast: true,
					},
				});
				return res;
			},

			// 选择文件后处理
			async uploadFile() {
				const fileRes = await uni.chooseVideo({
					sourceType: ['album', 'camera'],
					compressed: false
				});

				const file = fileRes; // 注意：uniapp返回的是临时路径
				console.log('选择的文件:', fileRes);

				// 需要先将文件进行处理
				await this.constructor(file);

				// 2. 检查上传状态
				const res = await this.checkStatus(file);

				if (res.exists) {
					console.log('文件已存在，无需上传');
					return res.file;
				}

				if (res.uploadedChunks.length > 0) {
					console.log(`发现已上传分片: ${res.uploadedChunks.length}个`);
				}

				// 3. 上传缺失的分片
				for (let i = 0; i < this.totalChunks; i++) {
					if (!res.uploadedChunks.includes(i)) {
						await this.uploadChunk(i, file);
					}
				}

				// 通知后端合并分片
				return await this.mergeChunks(file);
			},
			async uploadChunk(index, file) {
				const start = index * this.chunkSize;
				const end = Math.min(start + this.chunkSize, file.size);
				let chunk = null;
				// #ifdef H5
				chunk = file.tempFile.slice(start, end);
				// #endif

				// #ifndef H5
				// 小程序环境，通过uni.readFile读取文件分片
				chunk = await new Promise((resolve, reject) => {
					uni.readFile({
						filePath: file.tempFilePath,
						position: start,
						length: end - start,
						success: (res) => {
							// 创建一个包含ArrayBuffer的简单对象
							const chunkObj = {
								arrayBuffer: res.data,
								size: res.data.byteLength
							};
							resolve(chunkObj);
						},
						fail: reject
					});
				});
				// #endif

				let formData = {
					index: index,
					fileName: file.name,
					totalChunks: this.totalChunks,
					size: file.size,
					type: file.tempFile.type,
					fileHash: this.fileHash,
					// chunkHash: await this.calculateFileHash(file.tempFile),
				};
				try {
					let res = await uploadFileName('document/upload', {
						custom: {
							auth: true,
							catch: true
						},
						name: 'chunk',
						file: chunk,
						formData
					})
					console.log(`分片 ${index} 上传成功`);
				} catch (error) {
					console.error(`分片 ${index} 上传失败:`, error);
					throw error;
				}
			},
			async mergeChunks(file) {
				try {
					const res = await postName('/document/merge', {
						fileName: file.name,
						totalChunks: this.totalChunks,
						fileHash: this.fileHash
					}, {
						custom: {
							auth: true,
							toast: true,
						},
					});
					console.log(res);
					if (res) {
						console.log('文件上传完成:', res);
						// 更新UI，显示上传成功
					}
				} catch (error) {
					console.error('文件合并失败:', error);
					throw error;
				}
			},

			routed(url) {
				uni.$uv.route({
					url: url,
					intercept(params, next) {
						console.log(params, next)
						uni.showLoading({
							title: '等待中...'
						})
						// 模拟处理等待
						setTimeout(() => {
							uni.hideLoading();
							next(true);
						}, 1000)
					}
				})
			}
		}
	}
</script>

<style scoped lang="scss">
	// 测试
	.bg-purple {
		background: #CED7E1;
	}

	.bg-purple-light {
		background: #e5e9f2;
	}

	.bg-purple-dark {
		background: #99a9bf;
	}
</style>